home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / idlelib / FormatParagraph.py < prev    next >
Text File  |  2005-10-18  |  6KB  |  149 lines

  1. # Extension to format a paragraph
  2.  
  3. # Does basic, standard text formatting, and also understands Python
  4. # comment blocks.  Thus, for editing Python source code, this
  5. # extension is really only suitable for reformatting these comment
  6. # blocks or triple-quoted strings.
  7.  
  8. # Known problems with comment reformatting:
  9. # * If there is a selection marked, and the first line of the
  10. #   selection is not complete, the block will probably not be detected
  11. #   as comments, and will have the normal "text formatting" rules
  12. #   applied.
  13. # * If a comment block has leading whitespace that mixes tabs and
  14. #   spaces, they will not be considered part of the same block.
  15. # * Fancy comments, like this bulleted list, arent handled :-)
  16.  
  17. import re
  18. from configHandler import idleConf
  19.  
  20. class FormatParagraph:
  21.  
  22.     menudefs = [
  23.         ('format', [   # /s/edit/format   dscherer@cmu.edu
  24.             ('Format Paragraph', '<<format-paragraph>>'),
  25.          ])
  26.     ]
  27.  
  28.     def __init__(self, editwin):
  29.         self.editwin = editwin
  30.  
  31.     def close(self):
  32.         self.editwin = None
  33.  
  34.     def format_paragraph_event(self, event):
  35.         maxformatwidth = int(idleConf.GetOption('main','FormatParagraph','paragraph'))
  36.         text = self.editwin.text
  37.         first, last = self.editwin.get_selection_indices()
  38.         if first and last:
  39.             data = text.get(first, last)
  40.             comment_header = ''
  41.         else:
  42.             first, last, comment_header, data = \
  43.                     find_paragraph(text, text.index("insert"))
  44.         if comment_header:
  45.             # Reformat the comment lines - convert to text sans header.
  46.             lines = data.split("\n")
  47.             lines = map(lambda st, l=len(comment_header): st[l:], lines)
  48.             data = "\n".join(lines)
  49.             # Reformat to maxformatwidth chars or a 20 char width, whichever is greater.
  50.             format_width = max(maxformatwidth - len(comment_header), 20)
  51.             newdata = reformat_paragraph(data, format_width)
  52.             # re-split and re-insert the comment header.
  53.             newdata = newdata.split("\n")
  54.             # If the block ends in a \n, we dont want the comment
  55.             # prefix inserted after it. (Im not sure it makes sense to
  56.             # reformat a comment block that isnt made of complete
  57.             # lines, but whatever!)  Can't think of a clean soltution,
  58.             # so we hack away
  59.             block_suffix = ""
  60.             if not newdata[-1]:
  61.                 block_suffix = "\n"
  62.                 newdata = newdata[:-1]
  63.             builder = lambda item, prefix=comment_header: prefix+item
  64.             newdata = '\n'.join(map(builder, newdata)) + block_suffix
  65.         else:
  66.             # Just a normal text format
  67.             newdata = reformat_paragraph(data, maxformatwidth)
  68.         text.tag_remove("sel", "1.0", "end")
  69.         if newdata != data:
  70.             text.mark_set("insert", first)
  71.             text.undo_block_start()
  72.             text.delete(first, last)
  73.             text.insert(first, newdata)
  74.             text.undo_block_stop()
  75.         else:
  76.             text.mark_set("insert", last)
  77.         text.see("insert")
  78.  
  79. def find_paragraph(text, mark):
  80.     lineno, col = map(int, mark.split("."))
  81.     line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
  82.     while text.compare("%d.0" % lineno, "<", "end") and is_all_white(line):
  83.         lineno = lineno + 1
  84.         line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
  85.     first_lineno = lineno
  86.     comment_header = get_comment_header(line)
  87.     comment_header_len = len(comment_header)
  88.     while get_comment_header(line)==comment_header and \
  89.               not is_all_white(line[comment_header_len:]):
  90.         lineno = lineno + 1
  91.         line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
  92.     last = "%d.0" % lineno
  93.     # Search back to beginning of paragraph
  94.     lineno = first_lineno - 1
  95.     line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
  96.     while lineno > 0 and \
  97.               get_comment_header(line)==comment_header and \
  98.               not is_all_white(line[comment_header_len:]):
  99.         lineno = lineno - 1
  100.         line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
  101.     first = "%d.0" % (lineno+1)
  102.     return first, last, comment_header, text.get(first, last)
  103.  
  104. def reformat_paragraph(data, limit):
  105.     lines = data.split("\n")
  106.     i = 0
  107.     n = len(lines)
  108.     while i < n and is_all_white(lines[i]):
  109.         i = i+1
  110.     if i >= n:
  111.         return data
  112.     indent1 = get_indent(lines[i])
  113.     if i+1 < n and not is_all_white(lines[i+1]):
  114.         indent2 = get_indent(lines[i+1])
  115.     else:
  116.         indent2 = indent1
  117.     new = lines[:i]
  118.     partial = indent1
  119.     while i < n and not is_all_white(lines[i]):
  120.         # XXX Should take double space after period (etc.) into account
  121.         words = re.split("(\s+)", lines[i])
  122.         for j in range(0, len(words), 2):
  123.             word = words[j]
  124.             if not word:
  125.                 continue # Can happen when line ends in whitespace
  126.             if len((partial + word).expandtabs()) > limit and \
  127.                partial != indent1:
  128.                 new.append(partial.rstrip())
  129.                 partial = indent2
  130.             partial = partial + word + " "
  131.             if j+1 < len(words) and words[j+1] != " ":
  132.                 partial = partial + " "
  133.         i = i+1
  134.     new.append(partial.rstrip())
  135.     # XXX Should reformat remaining paragraphs as well
  136.     new.extend(lines[i:])
  137.     return "\n".join(new)
  138.  
  139. def is_all_white(line):
  140.     return re.match(r"^\s*$", line) is not None
  141.  
  142. def get_indent(line):
  143.     return re.match(r"^(\s*)", line).group()
  144.  
  145. def get_comment_header(line):
  146.     m = re.match(r"^(\s*#*)", line)
  147.     if m is None: return ""
  148.     return m.group(1)
  149.